﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using NPMonitor.DataModel;
using NPMonitor.Helpers;
using NPMonitor.Implementation.Internal;
using NPMonitor.Interfaces;
using NPMonitor.DataModel.Report;
using System.Data.SqlClient;
using NPMonitor.Utility;
using System.Data;
using System.Globalization;

namespace NPMonitor.Implementation.Store
{
    public class ReportStore : IReportStore
    {
        private List<string> SetXValue(ReportType reportType, string beginTime, string endTime)
        {
            DateTime begintime = Convert.ToDateTime(beginTime, Utils.SystemCulture);
            DateTime endtime = Convert.ToDateTime(endTime, Utils.SystemCulture);
            var xValue = new List<string>();
            if (endtime > begintime)
            {
                TimeSpan interval = endtime - begintime;
                int count = 0;
                switch (reportType)
                {
                    case ReportType.Daily:
                        int hourOfBegintime = begintime.Hour;
                        int hourOfEndtime = endtime.Hour;
                        for (int i = hourOfBegintime; i < hourOfEndtime; i++)
                        {
                            xValue.Add(new DateTime(begintime.Year, begintime.Month, begintime.Day, i, 0, 0).ToDateHourString());
                        }
                        break;
                    case ReportType.Hourly:
                        var starttime = begintime.Minute / 5 * 5;
                        var finishtime = endtime.Minute / 5 * 5;
                        for (int i = starttime; i <= finishtime; i+=5)
                        {
                            xValue.Add (new DateTime(begintime.Year, begintime.Month, begintime.Day, begintime.Hour, i, 0).ToDateHourString()); 
                        }
                            break;
                    case ReportType.Monthly:
                        count = Convert.ToInt32(interval.TotalDays);
                        for (int i = 0; i < count+1; i++)
                        {
                            DateTime time = begintime.AddDays(i);
                            xValue.Add(time.ToDateString());
                        }
                        break;
                    case ReportType.Yearly:
                        var starttimeMonth = begintime.Month;
                        var finishtimeMonth = endtime.Month;
                        for (int i = starttimeMonth; i <= finishtimeMonth; i++)
                        {
                            xValue.Add(new DateTime(begintime.Year, i, 1).ToYearlyDateString());
                        }
                        break;
                }
            }
            return xValue;
        }

        public List<Scenario> GetScenarioNoByJobId(int jobId)
        {
            using (var ctx = new DbStoreContext())
            {
                return ctx.Scenarios.Where(x => x.JobId == jobId && x.Enabled == true).ToList();
            }
        }

        public string GetLocationNameById(int poolId)
        {
            using (var ctx = new DbStoreContext())
            {
                return ctx.MachinePool.Where(x => x.PoolId == poolId).FirstOrDefault().PoolName;
            }
        }

        public List<ReportData> GetDailyReportDataByCondition(string scenarioNo, string beginTime, string endTime, params string[] locations)
        {
            List<ReportData> DailyReportData = new List<ReportData>();
            List<vDailyViewData> dailyReportData;
            SqlParameter scenarionoPar = new SqlParameter("scenariono", scenarioNo);
            SqlParameter beginTimePar = new SqlParameter("begintime", beginTime.ToDateTimeByFormat());
            SqlParameter endTimePar = new SqlParameter("endTime", endTime.ToDateTimeByFormat());
            using (var ctx = new DbStoreContext())
            {
                string strSqlCommand = @"select * from vDailyReport where scenarioNo = @scenariono and begintime between @begintime and @endTime";
                dailyReportData = ctx.Database.SqlQuery<vDailyViewData>(strSqlCommand, scenarionoPar, beginTimePar, endTimePar).ToList();
            }

            var xList = SetXValue(ReportType.Daily, beginTime, endTime);

            foreach (var item in locations)
            {
                var loccationId = Convert.ToInt32(item);
                var data = dailyReportData.Where(x => x.LocationId == loccationId);
                List<ChartPoint> points = new List<ChartPoint>();
                List<string> beginTimeList = new List<string>();
                ReportData rd = new ReportData();
                rd.Legend = GetLocationNameById(loccationId);
                rd.Group = scenarioNo;
                foreach (var locationdata in data)
                {
                    beginTimeList.Add(locationdata.BeginTime.ToDateHourString());
                    ChartPoint point = new ChartPoint() { AverageTime = locationdata.AverageTime, BeginTime = locationdata.BeginTime.ToDateHourString() };
                    points.Add(point);
                }

                #region add missing point

                List<ChartPoint> leftPointList = new List<ChartPoint>();

                foreach (var xvalue in xList)
                {
                    if (!beginTimeList.Contains(xvalue))
                    {
                        leftPointList.Add(new ChartPoint { AverageTime = 0, BeginTime = xvalue });
                    }
                }
                points.AddRange(leftPointList);

                #endregion

                rd.list = points.OrderBy(x => x.BeginTime).ToList();
                DailyReportData.Add(rd);
            }
            return DailyReportData;
        }

        public List<ReportData> GetHourlyReportDataByCondition(string scenarioNo, string beginTime, string endTime, params string[] locations)
        {
            List<ReportData> hourlyReportData = new List<ReportData>();
            List<vHourlyViewData> hourlyViewData;
            SqlParameter scenarionoPar = new SqlParameter("scenariono", scenarioNo);
            SqlParameter beginTimePar = new SqlParameter("begintime", beginTime.ToDateTimeByFormat());
            SqlParameter endTimePar = new SqlParameter("endTime", endTime.ToDateTimeByFormat());
            using (var ctx = new DbStoreContext())
            {
                string strSqlCommand = @"select * from vHourlyReport where scenarioNo = @scenariono and begintime between @begintime and @endTime";
                hourlyViewData = ctx.Database.SqlQuery<vHourlyViewData>(strSqlCommand, scenarionoPar, beginTimePar, endTimePar).ToList();
            }

            var xList = SetXValue(ReportType.Hourly, beginTime, endTime);

            foreach (var item in locations)
            {
                var loccationId = Convert.ToInt32(item);
                var data = hourlyViewData.Where(x => x.LocationId == loccationId);
                List<ChartPoint> points = new List<ChartPoint>();
                List<string> beginTimeList = new List<string>();
                ReportData rd = new ReportData();
                rd.Legend = GetLocationNameById(loccationId);
                rd.Group = scenarioNo;
                foreach (var locationdata in data)
                {
                    beginTimeList.Add(locationdata.BeginTime.ToDateHourString());
                    ChartPoint point = new ChartPoint() { AverageTime = locationdata.AverageTime, BeginTime = locationdata.BeginTime.ToDateHourString() };
                    points.Add(point);
                }
                #region add missing point
                List<ChartPoint> leftPointList = new List<ChartPoint>();
               
                foreach (var xvalue in xList)
                {
                    if (!beginTimeList.Contains(xvalue))
                    {
                        leftPointList.Add(new ChartPoint { AverageTime = 0, BeginTime = xvalue });
                    }
                }
                points.AddRange(leftPointList);
                #endregion
                rd.list = points.OrderBy(x => x.BeginTime).ToList();
                hourlyReportData.Add(rd);
            }
            return hourlyReportData;
        }

        public List<ReportData> GetWeeklyMonthlyReportDataByCondition(string scenarioNo, string beginTime, string endTime, params string[] locations)
        {
            List<ReportData> monthlyReportData = new List<ReportData>();
            List<vWeeklyViewData> weeklyViewData;
            SqlParameter scenarionoPar = new SqlParameter("scenariono", scenarioNo);
            SqlParameter beginTimePar = new SqlParameter("begintime", beginTime.ToDateTimeByFormat());
            SqlParameter endTimePar = new SqlParameter("endTime", endTime.ToDateTimeByFormat());
            using (var ctx = new DbStoreContext())
            {
                string strSqlCommand = @"select * from vMonthlyReport where scenarioNo = @scenariono and begintime between @begintime and @endTime";
                weeklyViewData = ctx.Database.SqlQuery<vWeeklyViewData>(strSqlCommand, scenarionoPar, beginTimePar, endTimePar).ToList();
            }
            var xList = SetXValue(ReportType.Monthly, beginTime, endTime);
            foreach (var item in locations)
            {
                var loccationId = Convert.ToInt32(item);
                var data = weeklyViewData.Where(x => x.LocationId == loccationId);
                List<ChartPoint> points = new List<ChartPoint>();
                List<string> beginTimeList = new List<string>();
                ReportData rd = new ReportData();
                rd.Legend = GetLocationNameById(loccationId);
                rd.Group = scenarioNo;
                foreach (var locationdata in data)
                {
                    beginTimeList.Add(locationdata.BeginTime.ToDateString());
                    ChartPoint point = new ChartPoint() { AverageTime = locationdata.AverageTime, BeginTime = locationdata.BeginTime.ToDateString() };
                    points.Add(point);
                }
                #region add missing point
                List<ChartPoint> leftPointList = new List<ChartPoint>();
                foreach (var xvalue in xList)
                {
                    if (!beginTimeList.Contains(xvalue))
                    {
                        leftPointList.Add(new ChartPoint { AverageTime = 0, BeginTime = xvalue });
                    }
                }
                points.AddRange(leftPointList);
                #endregion
                rd.list = points.OrderBy(x => x.BeginTime).ToList();
                monthlyReportData.Add(rd);
            }
            return monthlyReportData;

        }

        public List<ReportData> GetYearlyReportDataByCondition(string scenarioNo, string beginTime, string endTime, params string[] locations)
        {
            List<ReportData> yearlyReportData = new List<ReportData>();
            List<vYearlyViewData> yearlyViewData;
            SqlParameter scenarionoPar = new SqlParameter("scenariono", scenarioNo);
            SqlParameter beginTimePar = new SqlParameter("begintime", beginTime.ToDateTimeByFormat());
            SqlParameter endTimePar = new SqlParameter("endTime", endTime.ToDateTimeByFormat());
            using (var ctx = new DbStoreContext())
            {
                string strSqlCommand = @"select * from vYearlyReport where scenarioNo = @scenariono and begintime >= @begintime and begintime <= @endTime";
                yearlyViewData = ctx.Database.SqlQuery<vYearlyViewData>(strSqlCommand, scenarionoPar, beginTimePar, endTimePar).ToList();
            }
            var xList = SetXValue(ReportType.Yearly, beginTime, endTime);
            foreach (var item in locations)
            {
                var loccationId = Convert.ToInt32(item);
                var data = yearlyViewData.Where(x => x.LocationId == loccationId);
                List<ChartPoint> points = new List<ChartPoint>();
                List<string> beginTimeList = new List<string>();
                ReportData rd = new ReportData();
                rd.Legend = GetLocationNameById(loccationId);
                rd.Group = scenarioNo;
                foreach (var locationdata in data)
                {
                    beginTimeList.Add(locationdata.BeginTime.ToYearlyDateString());
                    ChartPoint point = new ChartPoint() { AverageTime = locationdata.AverageTime, BeginTime = locationdata.BeginTime.ToYearlyDateString() };
                    points.Add(point);
                }
                #region add missing point
                List<ChartPoint> leftPointList = new List<ChartPoint>();
                foreach (var xvalue in xList)
                {
                    if (!beginTimeList.Contains(xvalue))
                    {
                        leftPointList.Add(new ChartPoint { AverageTime = 0, BeginTime = xvalue });
                    }
                }
                points.AddRange(leftPointList);
                #endregion
                rd.list = points.OrderBy(x => x.BeginTime).ToList();
                yearlyReportData.Add(rd);
            }

            return yearlyReportData;
        }

        public List<ReportData> GetCumulativeTimeAvgReportData(int locationId, string beginTime, string endTime, params string[] scenarioNoList)
        {
            List<ReportData> DailyReportData = new List<ReportData>();

            List<vCumulativeTimeAvgViewData> dailyReportData;
            SqlParameter locationIdPar = new SqlParameter("locationId", locationId);
            SqlParameter beginTimePar = new SqlParameter("beginTime", beginTime.ToDateTimeByFormat());
            SqlParameter endTimePar = new SqlParameter("endTime", endTime.ToDateTimeByFormat());
            using (var ctx = new DbStoreContext())
            {
                string strSqlCommand = @"select * from vCumulativeTimeAvg where LocationId = @locationId and begintime between @beginTime and @endTime";
                dailyReportData = ctx.Database.SqlQuery<vCumulativeTimeAvgViewData>(strSqlCommand, locationIdPar, beginTimePar, endTimePar).ToList();
            }

            string locationName = GetLocationNameById(locationId);
            
            var xList = SetXValue(ReportType.Daily, beginTime, endTime);

            foreach (var item in scenarioNoList)
            {
                var data = dailyReportData.Where(x => x.ScenarioNo == item);
                List<ChartPoint> points = new List<ChartPoint>();
                List<string> beginTimeList = new List<string>();

                ReportData rd = new ReportData();

                rd.Group = locationName;
                rd.Legend = StoreManager.Current.JobDefinitionStore.GetScenarioByNo(item).ScenarioName;

                foreach (var scenariodata in data)
                {
                    string tBeginTime = scenariodata.BeginTime.Value.ToDateHourString();

                    beginTimeList.Add(tBeginTime);
                    ChartPoint point = new ChartPoint() { AverageTime = scenariodata.AverageTime, BeginTime = tBeginTime };
                    points.Add(point);
                }

                #region add missing point

                List<ChartPoint> leftPointList = new List<ChartPoint>();

                foreach (var xvalue in xList)
                {
                    if (!beginTimeList.Contains(xvalue))
                    {
                        leftPointList.Add(new ChartPoint { AverageTime = 0, BeginTime = xvalue });
                    }
                }

                points.AddRange(leftPointList);

                #endregion

                rd.list = points.OrderBy(x => x.BeginTime).ToList();
                DailyReportData.Add(rd);
            }
            return DailyReportData;
        }

        public List<HttpActionData> GetHttpActonList(string scenarioNo, DateTime beginTime, TimeSpan duration)
        {
            using (var ctx = new DbStoreContext())
            {
                DateTime endTime = beginTime.Add(duration);

                return ctx.HttpActions.Where(m => 
                    m.ScenarioNO == scenarioNo
                    && m.BeginTime >= beginTime && m.BeginTime < endTime).ToList();
            }
        }

        public ReportRefrenceData GetBaseLine(string scenarioNo)
        {
            using (var ctx = new DbStoreContext())
            {
                var scenario = ctx.Scenarios.FirstOrDefault(x => x.ScenarioNO == scenarioNo);
                return new ReportRefrenceData() { Legend = "Refrence", RefrenceTime = scenario.BaseTime==null?0:scenario.BaseTime.Value };
            }
        }

        public int GetScenarioBaseTime(string scenarioNo)
        {
            Scenario scenario = new Scenario();
            using (var ctx = new DbStoreContext())
            {
                scenario = ctx.Scenarios.FirstOrDefault(x => x.ScenarioNO == scenarioNo);
            }
            return scenario.BaseTime != null ? scenario.BaseTime.Value : 0;
        }

        public List<HttpActionRequestsData> GetHttpActionRequestsByActionId(long actionId)
        {
            List<HttpActionRequestsData> requestsList = new List<HttpActionRequestsData>();
            using (var ctx = new DbStoreContext())
            {
                requestsList = ctx.HttpActionRequests.Where(x => x.ActionId == actionId).ToList();
            }
            return requestsList;
        }

        public Scenario GetScenarioByActionId(long actionId)
        {
            Scenario scenario = new Scenario();
            SqlParameter actionIdPar = new SqlParameter("actionId", actionId);
            string sqlCommand = @"select *, [desc] as description from dbo.Scenarios
                                    where ScenarioNO =
                                        (select ScenarioNO from dbo.HttpActions 
                                            where ActionId= @actionId) ";
            using (var ctx = new DbStoreContext())
            {
                scenario = ctx.Database.SqlQuery<Scenario>(sqlCommand, actionIdPar).FirstOrDefault();
            }
            return scenario;
        }


        
    }
}
